package cn.lg.soar.common.util.lambda;

import cn.lg.soar.common.util.data.StringUtil;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Lambda 工具
 * @author luguoxiang
 * @date 2022/9/4
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public abstract class LambdaUtils {

    /**
     * 通过getter的方法引用获取字段名
     */
    public static <T> String getterToFieldName(IGetter<T, ?> getter) {
        try {
            Method method = getter.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda lambda = (SerializedLambda) method.invoke(getter);
            String methodName = lambda.getImplMethodName();
            String prefix;
            if (methodName.startsWith("get")) {
                prefix = "get";
            } else if (methodName.startsWith("is")) {
                prefix = "is";
            } else {
                throw new RuntimeException("无效的getter方法: " + methodName);
            }
            return StringUtil.lowerFirstCase(methodName.replace(prefix, ""));
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过setter的方法引用获取字段名
     */
    public static <T, U> String setterToFieldName(ISetter<T, U> setter) {
        try {
            Method method = setter.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda lambda = (SerializedLambda) method.invoke(setter);
            String methodName = lambda.getImplMethodName();
            if (methodName.startsWith("set")) {
                return StringUtil.lowerFirstCase(methodName.replace("set", ""));
            }
            throw new RuntimeException("无效的setter方法：" + methodName);
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 关键在于这个方法
     */
    public static SerializedLambda getSerializedLambda(Serializable fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            return (SerializedLambda) method.invoke(fn);
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
